#include "mqtt.h"

extern USARTBuffer usart_buffer;

u8 AtRxBuffer[512];     // 接收缓冲区
int errcount = 0;       // 错误标志位
int Rxcouter = 0;       // 接收计数器
int onenetdata_len = 0; // 数据长度

/// 发送字符型数据
void Send_HttpPkt(char *phead, char *pbody, char *dev_id)
{
    char sendBuf1[500];
    char *strx;
    char device_id[20] = {0};                                                               // 设备的ID
    USART_SendString(USART2, "AT+QIOPEN=1,0,\042TCP\042,\042183.230.40.33\042,80,0,1\r\n"); // 和ONENET服务器进行连接
    delay_ms(500);
    strx = strstr((const char *)AtRxBuffer, (const char *)"+QIOPEN: 0,0"); // 检查是否登陆成功
    errcount = 0;
    while (strx == NULL)
    {
        errcount++;
        strx = strstr((const char *)AtRxBuffer, (const char *)"+QIOPEN: 0,0"); // 检查是否登陆成功
        delay_ms(100);
        if (errcount > 50) // 防止死循环如果失败就重启板子
        {
            errcount = 0;
            break;
        }
    }
    delay_ms(500);
    Clear_Buffer(); // 服务器登录成功
    sprintf(sendBuf1, "%s%d\r\n\r\n%s", phead, strlen(pbody), pbody);
    USART_SendString(USART2, "AT+QISEND=0\r\n"); // 发送命令 反馈大于号
    delay_ms(500);
    // 发送内容
    USART_SendString(USART2, sendBuf1); // 刚才组建的发走
    delay_ms(100);
    USART_SendData(USART2, (u8)0x1a); // 发送完成函数发送结束符
    while (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET)
    {
    }
    delay_ms(3000); // 等待ONENET返回数据
    /* 分析id */
    if (Rxcouter > 0) // 读取到数据了
    {
        char *p = NULL, *pend = NULL;
        printf("rcv response:\r\n%s\r\n", AtRxBuffer);

        /* 获取设备ID */
        if ((p = strstr((char *)AtRxBuffer, "device_id")) != NULL)
        {
            p += strlen("device_id\":\"");
            if ((pend = strstr(p, "\",")) != NULL)
            {
                memcpy(device_id, p, pend - p); // device_id 存放设备ID
                memcpy(dev_id, p, pend - p);    // 获取ID号 dev_id存放设备ID
                printf("\r\n从ONENET获取的设备ID是: %s\r\n", device_id);
            }
        }
    }
    // 没有信息返回
    else if (Rxcouter == 0)
    {
        printf("XXXXXXXXXX服务器应答超时XXXXXXXXXX!\r\n");
    } // 设备为空
    else if (device_id[0] == 0)
    {
        printf("XXXXXXXXXX服务器没有该设备XXXXXXXXXX!\r\n");
    }
    Clear_Buffer();
}

// MQTT协议连接服务器
void MQTTCONNECTServer(void) // 连接MQTT服务器
{
    char *strx;
    // 先关闭之前的连接
    USART_SendString(USART2, "AT+QICLOSE=0\r\n");
    delay_ms(2000);
    strx = strstr((const char *)AtRxBuffer, (const char *)"OK"); // 检查是否关闭成功
    errcount = 0;
    while (strx == NULL)
    {
        strx = strstr((const char *)AtRxBuffer, (const char *)"OK"); // 检查是否关闭成功
        delay_ms(100);
        errcount++;
        if (errcount > 500) // 防止死循环如果失败就重启板子
        {
            errcount = 0;
            break;
        }
    }
    Clear_Buffer();
    delay_ms(1000);
    USART_SendString(USART2, "AT+QIOPEN=1,0,\042TCP\042,\042183.230.40.39\042,6002,0,1\r\n"); // TCP模式创建.采用MQTT方式去连接ONENET
    delay_ms(500);
    strx = strstr((const char *)AtRxBuffer, (const char *)"+QIOPEN: 0,0"); // 检查是否登陆成功
    errcount = 0;
    while (strx == NULL)
    {
        strx = strstr((const char *)AtRxBuffer, (const char *)"+QIOPEN: 0,0"); // 检查是否登陆成功
        delay_ms(100);
        errcount++;
        if (errcount > 500) // 防止死循环如果失败就重启板子
        {
            errcount = 0;
            break;
        }
    }
    delay_ms(500);
    Clear_Buffer();
}

// 发送MQTT数据包
void sendMQTTPkt(char *p, int len)
{
    char sendBuf[30] = {0};
    char *strx;
    strx = NULL;
    sprintf(sendBuf, "AT+QISEND=0,%d\r\n", len);
    USART_SendString(USART2, sendBuf); // 固定长度发数据
    delay_ms(500);
    strx = strstr((char *)AtRxBuffer, (char *)">");
    while (strx == NULL)
    {
        strx = strstr((char *)AtRxBuffer, (char *)">");
        delay_ms(100);
        errcount++;
        if (errcount > 500) // 防止死循环如果失败就重启板子
        {
            errcount = 0;
            break;
        }
    }
    USART_SendString(USART2, p);
    delay_ms(100);
}

// 对MQTT接收到的数据进行解析
int MqttSample_RecvPkt(void)
{
    u8 buffer[200];
    char *p = NULL;
    int i;
    onenetdata_len = 0; // 数据长度
    if (Rxcouter > 0)   // 有收到串口2就是4G模块反馈的信息，接收到数据了
    {
        memcpy(buffer, AtRxBuffer, Rxcouter);
        printf("\r\n我们需要解析的数据是: %s \r\n", buffer);
        /* 对接收到的数据进行解析 */
        if (strstr((char *)buffer, "+QIURC: \"closed\""))
        {
            __set_FAULTMASK(1); // 关闭总中断
            NVIC_SystemReset(); // 请求单片机复位
        }
        if ((p = uartDataParse((char *)buffer, &onenetdata_len)) == NULL) // 如果没有收到任何数据，表明失败
        {
            printf("No server Data\r\n");
            /* 返回0 */
            return 0;
        }
        memcpy(buffer, p, onenetdata_len);
        // 把收到的信息都打印出来
        if (onenetdata_len > 0)
        {
            printf("Rcv: \r\n");
            for (i = 0; i < onenetdata_len; i++)
            {
                printf("%02X ", ((unsigned char *)buffer)[i]);
            }
            printf("\r\n");
        }
        // 收到4个字节并且0 1 分别是0X20,0X02
        if (onenetdata_len == 4)
        {
            if (buffer[0] == 0x20 && buffer[1] == 0x02) // 返回CONNECT ACK连接状态
            {
                printf("Connect ONENET OK!\r\n");
            }
            if (buffer[0] == 0x40 && buffer[1] == 0x02) // 返回PUB ACK确认状态
            {
                printf("REC OK,PUB NO ACK !\r\n");
            }
        }
        return onenetdata_len;
    }
    return 0;
}
char *uartDataParse(char *buffer, int32_t *plen)
{
    char *p;
    char *pnum;
    int32_t len;
    if ((p = strstr(buffer, "CLOSED")) != NULL) // 表明MQTT连接失败
    {
        printf("tcp connection closed\r\n");
    }
    if ((p = strstr(buffer, "recv")) != NULL) // 有数据产生
    {
        p = strstr(p, ",");      // 判断第一个逗号的位置
        pnum = p + 3;            // 获取数据长度
        p = strstr(p + 1, "\n"); // 获取第二个逗号的位置
        *(p++) = '\0';           // 添加结束符
        len = atoi(pnum);
        printf("rcv %d data from OneNET:\r\n", len);
        *plen = len;
        return p;
    }

    return NULL;
}

// 访问ONENET需要提交JSON数据
u8 MqttOnenet_Savedata(u8 *t_payload, float lon, float lat)
{
    char json[] = "{\"datastreams\":[{\"id\":\"location\",\"datapoints\":[{\"value\":{\"lon\":%2.6f,\"lat\":%2.6f}}]}]}";
    char t_json[200];
    int payload_len;
    unsigned short json_len;
    payload_len = payload_len;
    sprintf(t_json, json, lon, lat);
    payload_len = 1 + 2 + strlen(t_json) / sizeof(char);
    json_len = strlen(t_json) / sizeof(char);
    // type
    t_payload[0] = '\x01';
    // length
    t_payload[1] = (json_len & 0xFF00) >> 8;
    t_payload[2] = json_len & 0xFF;
    // json
    memcpy(t_payload + 3, t_json, json_len);
    return json_len + 3;
}

// 发送用户变量 比如温湿度
u8 MqttOnenet_SavedataTEMP(u8 *t_payload, u8 temp, u8 humi)
{
    char json[] = "{\"datastreams\":[{\"id\":\"temp\",\"datapoints\":[{\"value\":%d}]},{\"id\":\"humi\",\"datapoints\":[{\"value\":%d}]}]}";
    char t_json[200];
    int payload_len;
    unsigned short json_len;
    payload_len = payload_len;
    sprintf(t_json, json, temp, humi);
    payload_len = 1 + 2 + strlen(t_json) / sizeof(char);
    json_len = strlen(t_json) / sizeof(char);
    // type
    t_payload[0] = '\x01';
    // length
    t_payload[1] = (json_len & 0xFF00) >> 8;
    t_payload[2] = json_len & 0xFF;
    // json
    memcpy(t_payload + 3, t_json, json_len);
    return json_len + 3;
}

// PROD_ID,SN,id
// 构建MQTT连接包
u16 mqtt_connect_message(u8 *mqtt_message, char *client_id, char *username, char *password)
{
    u16 client_id_length = strlen(client_id);
    u16 username_length = strlen(username);
    u16 password_length = strlen(password);
    u16 packetLen;
    u16 i, baseIndex;
    packetLen = 12 + 2 + client_id_length;
    if (username_length > 0)
        packetLen = packetLen + 2 + username_length;
    if (password_length > 0)
        packetLen = packetLen + 2 + password_length;
    mqtt_message[0] = 0x10;          // 0x10 // MQTT Message Type CONNECT
    mqtt_message[1] = packetLen - 2; // 剩余长度(不包括固定头部)
    baseIndex = 2;
    if (packetLen > 127)
    {
        mqtt_message[2] = 1; // packetLen/127;
        baseIndex = 3;
    }
    mqtt_message[baseIndex++] = 0;                                // Protocol Name Length MSB
    mqtt_message[baseIndex++] = 4;                                // Protocol Name Length LSB
    mqtt_message[baseIndex++] = 77;                               // ASCII Code for M
    mqtt_message[baseIndex++] = 81;                               // ASCII Code for Q
    mqtt_message[baseIndex++] = 84;                               // ASCII Code for T
    mqtt_message[baseIndex++] = 84;                               // ASCII Code for T
    mqtt_message[baseIndex++] = 4;                                // MQTT Protocol version = 4
    mqtt_message[baseIndex++] = 0xc0;                             // conn flags ,要清除掉前面的连接标志
    mqtt_message[baseIndex++] = 0;                                // Keep-alive Time Length MSB
    mqtt_message[baseIndex++] = 120;                              // Keep-alive Time Length LSB    120s
    mqtt_message[baseIndex++] = (0xff00 & client_id_length) >> 8; // Client ID length MSB
    mqtt_message[baseIndex++] = 0xff & client_id_length;          // Client ID length LSB
    // Client ID
    for (i = 0; i < client_id_length; i++)
    {
        mqtt_message[baseIndex + i] = client_id[i];
    }
    baseIndex = baseIndex + client_id_length;
    if (username_length > 0)
    {
        // username
        mqtt_message[baseIndex++] = (0xff00 & username_length) >> 8; // username length MSB
        mqtt_message[baseIndex++] = 0xff & username_length;          // username length LSB
        for (i = 0; i < username_length; i++)
        {
            mqtt_message[baseIndex + i] = username[i];
        }
        baseIndex = baseIndex + username_length;
    }
    if (password_length > 0)
    {
        // password
        mqtt_message[baseIndex++] = (0xff00 & password_length) >> 8; // password length MSB
        mqtt_message[baseIndex++] = 0xff & password_length;          // password length LSB
        for (i = 0; i < password_length; i++)
        {
            mqtt_message[baseIndex + i] = password[i];
        }
        baseIndex += password_length;
    }
    return baseIndex;
}

// 构建MQTT发布消息包
u16 mqtt_publish_message(u8 *mqtt_message, char *topic, char *message, u8 qos)
{
    u16 topic_length = strlen(topic);
    u16 message_length = strlen(message);
    u16 i, index = 0;
    static u16 id = 2;
    mqtt_message[index++] = 0x32; // 0x32 // MQTT Message Type PUBLISH
    if (qos)
        mqtt_message[index++] = 2 + topic_length + 2 + message_length;
    else
        mqtt_message[index++] = 2 + topic_length + message_length; // Remaining length
    mqtt_message[index++] = (0xff00 & topic_length) >> 8;
    mqtt_message[index++] = 0xff & topic_length;
    // Topic
    for (i = 0; i < topic_length; i++)
    {
        mqtt_message[index + i] = topic[i];
    }
    index += topic_length;
    if (qos)
    {
        mqtt_message[index++] = (0xff00 & id) >> 8;
        mqtt_message[index++] = 0xff & id;
        ///	id++;
    }
    // Message
    for (i = 0; i < message_length; i++)
    {
        mqtt_message[index + i] = message[i];
    }
    index += message_length;
    return index;
}

// 构建MQTT_ONENET发布消息包
u16 mqtt_onenetpublish_message(u8 *mqtt_message, char *topic, char *message, u16 len, u8 qos)
{
    u16 topic_length = strlen(topic);
    u16 message_length;
    u16 i, index = 0;
    static u16 id = 1;
    message_length = len;
    mqtt_message[index++] = 0x32; // 0x32 // MQTT Message Type PUBLISH    要求有QOS等级
    if (qos)
        mqtt_message[index++] = 2 + topic_length + 2 + message_length; // 加载报文标志符
    else
        mqtt_message[index++] = 2 + topic_length + message_length; // Remaining length
    mqtt_message[index++] = (0xff00 & topic_length) >> 8;
    mqtt_message[index++] = 0xff & topic_length;
    // Topic
    for (i = 0; i < topic_length; i++)
    {
        mqtt_message[index + i] = topic[i];
    }
    index += topic_length;
    if (qos)
    {
        mqtt_message[index++] = (0xff00 & id) >> 8;
        mqtt_message[index++] = 0xff & id;
        // id++;报文标识符可以变进行测试
    }
    // Message
    for (i = 0; i < message_length; i++)
    {
        mqtt_message[index + i] = message[i];
    }
    index += message_length;
    return index;
}

// 构建MQTT发布确认包
// 对QoS级别1的 PUBLISH 消息的回应
// 当服务器发送 PUBLISH 消息给订阅者客户端，客户端回复 PUBACK 消息
u8 mqtt_puback_message(u8 *mqtt_message)
{
    static u16 id = 0;
    mqtt_message[0] = 64;                 // 0x40 //消息类型和标志 PUBACK
    mqtt_message[1] = 2;                  // 剩余长度(不包括固定头部)
    mqtt_message[2] = (0xff00 & id) >> 8; // 消息标识符
    mqtt_message[3] = 0xff & id;          // 消息标识符
    id++;
    return 4;
}

// 构建MQTT订阅请求/取消订阅包
// whether=1,订阅; whether=0,取消订阅
u16 mqtt_subscribe_message(u8 *mqtt_message, char *topic, u8 qos, u8 whether)
{
    u16 topic_len = strlen(topic);
    u16 i, index = 0;
    static u16 id = 3;
    if (whether)
        mqtt_message[index++] = 0x80; // 0x82 //消息类型和标志 SUBSCRIBE 订阅
    else
        mqtt_message[index++] = 162;                   // 0xA2 取消订阅
    mqtt_message[index++] = topic_len + 5;             // 剩余长度(不包括固定头部)
    mqtt_message[index++] = (0xff00 & id) >> 8;        // 消息标识符
    mqtt_message[index++] = 0xff & id;                 // 消息标识符
    mqtt_message[index++] = (0xff00 & topic_len) >> 8; // 主题长度(高位在前,低位在后)
    mqtt_message[index++] = 0xff & topic_len;          // 主题长度
    for (i = 0; i < topic_len; i++)
    {
        mqtt_message[index + i] = topic[i];
    }
    index += topic_len;
    if (whether)
    {
        mqtt_message[index] = qos; // QoS级别
        index++;
    }
    return index;
}

// 构建MQTT PING请求包
u8 mqtt_ping_message(u8 *mqtt_message)
{
    mqtt_message[0] = 0xC0; // 0xC0 //消息类型和标志 PING
    mqtt_message[1] = 0x00; // 剩余长度(不包括固定头部)
    return 2;
}

// 构建MQTT断开连接包
u8 mqtt_disconnect_message(u8 *mqtt_message)
{
    mqtt_message[0] = 0XE0; // 0xE0 //消息类型和标志 DISCONNECT
    mqtt_message[1] = 0;    // 剩余长度(不包括固定头部)
    return 2;
}

// 定义一个名为 Clear_Buffer 的函数，用于清空缓冲区
void Clear_Buffer(void)
{
    // 使用 memset 函数将 AtRxBuffer 缓冲区的 512 个字节全部设置为 0
    memset(AtRxBuffer, 0, 512);
}